# -*- coding: utf-8 -*-
"""视频管理器模块，负责管理多个视频处理器实例"""

import logging
import threading
import time
import json
import os
from typing import Dict, List, Optional, Any, Callable
from datetime import datetime

from .video_processor import VideoProcessor
from .scene_manager import SceneManager, get_scene_manager

logger = logging.getLogger(__name__)

class VideoManager:
    """视频管理器，负责管理多个摄像头的视频处理"""
    
    def __init__(self, config: Dict[str, Any] = None):
        """初始化视频管理器
        
        Args:
            config: 配置参数
        """
        self.config = config or {}
        self.processor_lock = threading.RLock()  # 用于保护处理器字典
        self.processors: Dict[str, VideoProcessor] = {}  # 摄像头ID -> 视频处理器
        
        # 外部组件引用
        self.detection_engine = None
        self.behavior_analyzer = None
        self.alert_manager = None
        self.scene_manager = None  # 场景管理器
        
        # 摄像头场景配置映射
        self.camera_scene_configs: Dict[str, Dict[str, Any]] = {}  # 摄像头ID -> 场景配置
        
        # 状态
        self.running = False
        self.initialized = False
        
        # 线程
        self.monitor_thread = None
        
        # 回调函数
        self.global_callbacks = {
            'on_frame': None,
            'on_processed_frame': None,
            'on_detection': None,
            'on_alert': None
        }
        
        # 摄像头配置
        self.camera_configs: Dict[str, Dict[str, Any]] = {}
        
        # 性能监控
        self.monitoring_enabled = self.config.get('enable_monitoring', True)
        self.monitoring_interval = self.config.get('monitoring_interval', 60)  # 秒
        
        # 数据存储配置
        self.storage_config = self.config.get('storage', {})
        
        logger.info("视频管理器初始化完成")
    
    def initialize(self, detection_engine=None, behavior_analyzer=None, alert_manager=None, scene_manager=None) -> bool:
        """初始化视频管理器
        
        Args:
            detection_engine: 检测引擎实例
            behavior_analyzer: 行为分析器实例
            alert_manager: 告警管理器实例
            scene_manager: 场景管理器实例
            
        Returns:
            bool: 初始化是否成功
        """
        try:
            logger.info("初始化视频管理器")
            
            # 设置外部组件引用
            self.detection_engine = detection_engine
            self.behavior_analyzer = behavior_analyzer
            self.alert_manager = alert_manager
            self.scene_manager = scene_manager or get_scene_manager()  # 使用传入的场景管理器或获取默认实例
            
            # 加载摄像头配置
            if not self._load_camera_configs():
                logger.error("加载摄像头配置失败")
                return False
            
            self.initialized = True
            logger.info("视频管理器初始化成功")
            return True
            
        except Exception as e:
            logger.error(f"初始化视频管理器失败: {str(e)}")
            return False
    
    def _load_camera_configs(self) -> bool:
        """加载摄像头配置
        
        Returns:
            bool: 是否成功
        """
        try:
            # 从配置中获取摄像头信息
            cameras = self.config.get('cameras', [])
            
            if not cameras:
                logger.warning("未配置任何摄像头")
                return True  # 没有配置摄像头也认为是成功的
            
            for camera_config in cameras:
                camera_id = camera_config.get('id')
                if not camera_id:
                    logger.error("摄像头配置缺少ID")
                    continue
                
                # 验证必要的配置
                if 'source' not in camera_config:
                    logger.error(f"摄像头 {camera_id} 缺少source配置")
                    continue
                
                self.camera_configs[camera_id] = camera_config
                logger.info(f"加载摄像头配置: {camera_id}, 源: {camera_config['source']}")
            
            logger.info(f"成功加载 {len(self.camera_configs)} 个摄像头配置")
            return True
            
        except Exception as e:
            logger.error(f"加载摄像头配置失败: {str(e)}")
            return False
    
    def start(self) -> bool:
        """启动视频管理器
        
        Returns:
            bool: 是否成功启动
        """
        try:
            if not self.initialized:
                logger.error("视频管理器尚未初始化")
                return False
            
            if self.running:
                logger.warning("视频管理器已经在运行")
                return True
            
            logger.info("启动视频管理器")
            self.running = True
            
            # 启动所有配置的摄像头处理器
            success_count = 0
            for camera_id, camera_config in self.camera_configs.items():
                if self.start_camera(camera_id, camera_config):
                    success_count += 1
                else:
                    logger.error(f"启动摄像头 {camera_id} 失败")
            
            logger.info(f"启动了 {success_count}/{len(self.camera_configs)} 个摄像头")
            
            # 启动监控线程
            if self.monitoring_enabled:
                self.monitor_thread = threading.Thread(
                    target=self._monitor_loop,
                    name="video-monitor",
                    daemon=True
                )
                self.monitor_thread.start()
            
            return True
            
        except Exception as e:
            logger.error(f"启动视频管理器失败: {str(e)}")
            self.running = False
            return False
    
    def stop(self) -> bool:
        """停止视频管理器
        
        Returns:
            bool: 是否成功停止
        """
        try:
            if not self.running:
                logger.warning("视频管理器已经停止")
                return True
            
            logger.info("停止视频管理器")
            self.running = False
            
            # 停止监控线程
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.monitor_thread.join(timeout=2.0)
                if self.monitor_thread.is_alive():
                    logger.warning("监控线程未正常结束")
            
            # 停止所有视频处理器
            with self.processor_lock:
                processor_ids = list(self.processors.keys())
                
            for camera_id in processor_ids:
                self.stop_camera(camera_id)
            
            logger.info("视频管理器停止成功")
            return True
            
        except Exception as e:
            logger.error(f"停止视频管理器失败: {str(e)}")
            return False
    
    def start_camera(self, camera_id: str, camera_config: Dict[str, Any] = None) -> bool:
        """启动指定摄像头
        
        Args:
            camera_id: 摄像头ID
            camera_config: 摄像头配置（可选）
            
        Returns:
            bool: 是否成功启动
        """
        try:
            # 检查是否已经运行
            with self.processor_lock:
                if camera_id in self.processors:
                    processor = self.processors[camera_id]
                    if processor.is_alive():
                        logger.warning(f"摄像头 {camera_id} 已经在运行")
                        return True
            
            # 获取配置
            if camera_config is None:
                if camera_id not in self.camera_configs:
                    logger.error(f"摄像头 {camera_id} 配置不存在")
                    return False
                camera_config = self.camera_configs[camera_id]
            
            # 获取场景配置
            scene_config = camera_config.get('scene', {})
            self.camera_scene_configs[camera_id] = scene_config
            
            # 为摄像头分配场景
            if self.scene_manager and scene_config.get('auto_detect', False):
                logger.info(f"为摄像头 {camera_id} 启用自动场景检测")
            elif self.scene_manager and scene_config.get('scene_id'):
                logger.info(f"为摄像头 {camera_id} 设置固定场景: {scene_config['scene_id']}")
            
            # 创建视频处理器
            processor = VideoProcessor(
                camera_id=camera_id,
                source=camera_config['source'],
                config=camera_config.get('processor', {})
            )
            
            # 设置回调函数
            processor_callbacks = {
                'on_frame': self._wrap_callback(self.global_callbacks['on_frame'], camera_id),
                'on_processed_frame': self._wrap_callback(self.global_callbacks['on_processed_frame'], camera_id),
                'on_detection': self._wrap_callback(self.global_callbacks['on_detection'], camera_id),
                'on_alert': self._on_alert  # 特殊处理告警回调
            }
            processor.set_callbacks(**processor_callbacks)
            
            # 初始化并启动处理器，传入场景管理器
            if not processor.initialize(self.detection_engine, self.behavior_analyzer, self.scene_manager):
                logger.error(f"初始化摄像头 {camera_id} 的处理器失败")
                return False
            
            if not processor.start():
                logger.error(f"启动摄像头 {camera_id} 的处理器失败")
                return False
            
            # 保存处理器引用
            with self.processor_lock:
                self.processors[camera_id] = processor
            
            logger.info(f"摄像头 {camera_id} 启动成功")
            return True
            
        except Exception as e:
            logger.error(f"启动摄像头 {camera_id} 失败: {str(e)}")
            return False
    
    def stop_camera(self, camera_id: str) -> bool:
        """停止指定摄像头
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            bool: 是否成功停止
        """
        try:
            with self.processor_lock:
                if camera_id not in self.processors:
                    logger.warning(f"摄像头 {camera_id} 未运行")
                    return True
                
                processor = self.processors[camera_id]
                
            # 停止处理器
            success = processor.stop()
            
            # 移除处理器引用
            if success:
                with self.processor_lock:
                    if camera_id in self.processors:
                        del self.processors[camera_id]
                logger.info(f"摄像头 {camera_id} 停止成功")
            else:
                logger.error(f"停止摄像头 {camera_id} 失败")
            
            return success
            
        except Exception as e:
            logger.error(f"停止摄像头 {camera_id} 时发生错误: {str(e)}")
            return False
    
    def restart_camera(self, camera_id: str) -> bool:
        """重启指定摄像头
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            bool: 是否成功重启
        """
        try:
            logger.info(f"重启摄像头 {camera_id}")
            
            # 停止摄像头
            if not self.stop_camera(camera_id):
                logger.error(f"停止摄像头 {camera_id} 失败，无法重启")
                return False
            
            # 短暂延迟
            time.sleep(0.5)
            
            # 重新启动摄像头
            return self.start_camera(camera_id)
            
        except Exception as e:
            logger.error(f"重启摄像头 {camera_id} 失败: {str(e)}")
            return False
    
    def get_camera_status(self, camera_id: str) -> Optional[Dict[str, Any]]:
        """获取摄像头状态
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            状态信息字典
        """
        try:
            with self.processor_lock:
                if camera_id not in self.processors:
                    return None
                
                processor = self.processors[camera_id]
            
            return processor.get_status()
            
        except Exception as e:
            logger.error(f"获取摄像头 {camera_id} 状态失败: {str(e)}")
            return None
    
    def get_all_camera_status(self) -> Dict[str, Dict[str, Any]]:
        """获取所有摄像头状态
        
        Returns:
            摄像头ID -> 状态信息的字典
        """
        status_dict = {}
        
        with self.processor_lock:
            processor_ids = list(self.processors.keys())
        
        for camera_id in processor_ids:
            status = self.get_camera_status(camera_id)
            if status:
                status_dict[camera_id] = status
        
        return status_dict
    
    def get_camera_snapshot(self, camera_id: str) -> Optional[Any]:
        """获取摄像头快照
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            图像数据
        """
        try:
            with self.processor_lock:
                if camera_id not in self.processors:
                    logger.warning(f"摄像头 {camera_id} 未运行")
                    return None
                
                processor = self.processors[camera_id]
            
            return processor.get_snapshot()
            
        except Exception as e:
            logger.error(f"获取摄像头 {camera_id} 快照失败: {str(e)}")
            return None
    
    def set_global_callbacks(self, **callbacks):
        """设置全局回调函数
        
        Args:
            callbacks: 回调函数字典
        """
        for name, callback in callbacks.items():
            if name in self.global_callbacks:
                self.global_callbacks[name] = callback
        
        # 更新现有处理器的回调
        with self.processor_lock:
            for processor in self.processors.values():
                processor.set_callbacks(
                    on_frame=self._wrap_callback(self.global_callbacks['on_frame'], processor.camera_id),
                    on_processed_frame=self._wrap_callback(self.global_callbacks['on_processed_frame'], processor.camera_id),
                    on_detection=self._wrap_callback(self.global_callbacks['on_detection'], processor.camera_id),
                    on_alert=self._on_alert
                )
    
    def _wrap_callback(self, callback: Optional[Callable], camera_id: str) -> Optional[Callable]:
        """包装回调函数，添加摄像头ID信息
        
        Args:
            callback: 原始回调函数
            camera_id: 摄像头ID
            
        Returns:
            包装后的回调函数
        """
        if not callback:
            return None
        
        def wrapped_callback(data):
            try:
                # 确保数据包含摄像头ID
                if isinstance(data, dict) and 'camera_id' not in data:
                    data['camera_id'] = camera_id
                return callback(data)
            except Exception as e:
                logger.error(f"执行回调函数失败 (摄像头 {camera_id}): {str(e)}")
        
        return wrapped_callback
    
    def _on_alert(self, alert_data: Dict[str, Any]):
        """处理告警
        
        Args:
            alert_data: 告警数据
        """
        try:
            # 首先调用全局告警回调
            if self.global_callbacks['on_alert']:
                self.global_callbacks['on_alert'](alert_data)
            
            # 然后通过告警管理器处理
            if self.alert_manager:
                self.alert_manager.process_alert(alert_data)
            
        except Exception as e:
            logger.error(f"处理告警失败: {str(e)}")
    
    def _monitor_loop(self):
        """监控循环，检查摄像头状态并自动重启异常的摄像头"""
        logger.info("启动视频监控循环")
        
        while self.running:
            try:
                # 检查每个处理器的状态
                with self.processor_lock:
                    processor_ids = list(self.processors.keys())
                
                for camera_id in processor_ids:
                    try:
                        processor = self.processors[camera_id]
                        
                        # 检查处理器是否正常运行
                        if not processor.is_alive():
                            logger.warning(f"检测到摄像头 {camera_id} 异常，尝试重启")
                            self.restart_camera(camera_id)
                        
                    except Exception as e:
                        logger.error(f"监控摄像头 {camera_id} 失败: {str(e)}")
                
                # 等待下一个监控周期
                for _ in range(self.monitoring_interval):
                    if not self.running:
                        break
                    time.sleep(1)
                    
            except Exception as e:
                logger.error(f"监控循环错误: {str(e)}")
                time.sleep(1)
        
        logger.info("视频监控循环结束")
    
    def update_camera_config(self, camera_id: str, config: Dict[str, Any]) -> bool:
        """更新摄像头配置
        
        Args:
            camera_id: 摄像头ID
            config: 新的配置
            
        Returns:
            bool: 是否成功更新
        """
        try:
            # 更新配置存储
            if camera_id not in self.camera_configs:
                self.camera_configs[camera_id] = {}
            
            self.camera_configs[camera_id].update(config)
            
            # 如果摄像头正在运行，更新处理器配置
            with self.processor_lock:
                if camera_id in self.processors:
                    processor = self.processors[camera_id]
                    processor.update_config(config.get('processor', {}))
            
            logger.info(f"更新摄像头 {camera_id} 配置成功")
            return True
            
        except Exception as e:
            logger.error(f"更新摄像头 {camera_id} 配置失败: {str(e)}")
            return False
    
    def add_camera(self, camera_config: Dict[str, Any]) -> bool:
        """添加新摄像头
        
        Args:
            camera_config: 摄像头配置
            
        Returns:
            bool: 是否成功添加
        """
        try:
            camera_id = camera_config.get('id')
            if not camera_id:
                logger.error("摄像头配置缺少ID")
                return False
            
            if 'source' not in camera_config:
                logger.error("摄像头配置缺少source")
                return False
            
            # 保存配置
            self.camera_configs[camera_id] = camera_config
            
            # 如果管理器正在运行，启动新摄像头
            if self.running:
                return self.start_camera(camera_id, camera_config)
            
            return True
            
        except Exception as e:
            logger.error(f"添加摄像头失败: {str(e)}")
            return False
    
    def remove_camera(self, camera_id: str) -> bool:
        """移除摄像头
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            bool: 是否成功移除
        """
        try:
            # 停止摄像头
            if not self.stop_camera(camera_id):
                logger.warning(f"停止摄像头 {camera_id} 失败，但继续移除")
            
            # 移除配置
            if camera_id in self.camera_configs:
                del self.camera_configs[camera_id]
            
            logger.info(f"移除摄像头 {camera_id} 成功")
            return True
            
        except Exception as e:
            logger.error(f"移除摄像头 {camera_id} 失败: {str(e)}")
            return False
    
    def get_active_cameras(self) -> List[str]:
        """获取当前活跃的摄像头列表
        
        Returns:
            活跃摄像头ID列表
        """
        with self.processor_lock:
            return list(self.processors.keys())
    
    def get_all_cameras(self) -> Dict[str, Dict[str, Any]]:
        """获取所有配置的摄像头
        
        Returns:
            摄像头ID -> 配置的字典
        """
        return self.camera_configs.copy()
    
    def is_camera_active(self, camera_id: str) -> bool:
        """检查摄像头是否活跃
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            bool: 是否活跃
        """
        with self.processor_lock:
            if camera_id not in self.processors:
                return False
            
            return self.processors[camera_id].is_alive()
    
    def set_camera_scene(self, camera_id: str, scene_id: str) -> bool:
        """为指定摄像头设置场景
        
        Args:
            camera_id: 摄像头ID
            scene_id: 场景ID
            
        Returns:
            bool: 设置是否成功
        """
        try:
            if not self.scene_manager:
                logger.error("场景管理器未初始化")
                return False
            
            if camera_id not in self.processors:
                logger.error(f"摄像头 {camera_id} 未运行")
                return False
            
            # 更新摄像头场景配置
            self.camera_scene_configs[camera_id] = {'scene_id': scene_id}
            
            # 通过场景管理器切换场景
            result = self.scene_manager.switch_scene(scene_id)
            if result:
                logger.info(f"为摄像头 {camera_id} 成功切换到场景: {scene_id}")
                # 通知对应处理器场景变化
                processor = self.processors[camera_id]
                if hasattr(processor, '_on_scene_changed'):
                    processor._on_scene_changed(scene_id)
            
            return result
            
        except Exception as e:
            logger.error(f"设置摄像头 {camera_id} 场景失败: {str(e)}")
            return False
    
    def enable_auto_scene_detection(self, camera_id: str, enable: bool = True) -> bool:
        """启用或禁用摄像头的自动场景检测
        
        Args:
            camera_id: 摄像头ID
            enable: 是否启用
            
        Returns:
            bool: 设置是否成功
        """
        try:
            if not self.scene_manager:
                logger.error("场景管理器未初始化")
                return False
            
            if camera_id not in self.processors:
                logger.error(f"摄像头 {camera_id} 未运行")
                return False
            
            # 更新摄像头场景配置
            self.camera_scene_configs[camera_id] = {'auto_detect': enable}
            
            if enable:
                logger.info(f"为摄像头 {camera_id} 启用自动场景检测")
            else:
                logger.info(f"为摄像头 {camera_id} 禁用自动场景检测")
            
            # 更新处理器配置
            processor = self.processors[camera_id]
            if hasattr(processor, 'update_config'):
                processor.update_config({'scene': {'auto_detect': enable}})
            
            return True
            
        except Exception as e:
            logger.error(f"设置摄像头 {camera_id} 自动场景检测失败: {str(e)}")
            return False
    
    def get_camera_scene(self, camera_id: str) -> Optional[str]:
        """获取摄像头当前场景
        
        Args:
            camera_id: 摄像头ID
            
        Returns:
            当前场景ID或None
        """
        try:
            if camera_id not in self.camera_scene_configs:
                return None
            
            scene_config = self.camera_scene_configs[camera_id]
            if scene_config.get('auto_detect', False):
                # 如果启用了自动检测，从场景管理器获取当前场景
                if self.scene_manager:
                    return self.scene_manager.get_current_scene_id()
            else:
                # 返回配置的固定场景
                return scene_config.get('scene_id')
            
            return None
            
        except Exception as e:
            logger.error(f"获取摄像头 {camera_id} 场景失败: {str(e)}")
            return None
    
    def _on_scene_changed(self, scene_id: str, camera_id: str = None):
        """场景变化处理回调
        
        Args:
            scene_id: 新场景ID
            camera_id: 触发场景变化的摄像头ID（可选）
        """
        try:
            logger.info(f"场景变化通知: {scene_id}, 触发摄像头: {camera_id}")
            
            # 更新相关摄像头的配置
            for cam_id, processor in self.processors.items():
                # 只更新启用了自动场景检测的摄像头
                if cam_id in self.camera_scene_configs:
                    scene_config = self.camera_scene_configs[cam_id]
                    if scene_config.get('auto_detect', False):
                        # 通知处理器场景变化
                        if hasattr(processor, '_on_scene_changed'):
                            processor._on_scene_changed(scene_id)
            
        except Exception as e:
            logger.error(f"处理场景变化通知失败: {str(e)}")
    
    def save_camera_configs(self, file_path: str) -> bool:
        """保存摄像头配置到文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            bool: 是否成功保存
        """
        try:
            # 确保目录存在
            dir_path = os.path.dirname(file_path)
            if dir_path and not os.path.exists(dir_path):
                os.makedirs(dir_path)
            
            # 将配置转换为列表格式
            cameras_list = list(self.camera_configs.values())
            
            # 保存到文件
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(cameras_list, f, ensure_ascii=False, indent=2)
            
            logger.info(f"成功保存摄像头配置到 {file_path}")
            return True
            
        except Exception as e:
            logger.error(f"保存摄像头配置失败: {str(e)}")
            return False
    
    def load_camera_configs_from_file(self, file_path: str) -> bool:
        """从文件加载摄像头配置
        
        Args:
            file_path: 文件路径
            
        Returns:
            bool: 是否成功加载
        """
        try:
            if not os.path.exists(file_path):
                logger.error(f"配置文件不存在: {file_path}")
                return False
            
            # 读取文件
            with open(file_path, 'r', encoding='utf-8') as f:
                cameras_list = json.load(f)
            
            # 更新配置
            self.camera_configs.clear()
            for camera_config in cameras_list:
                camera_id = camera_config.get('id')
                if camera_id:
                    self.camera_configs[camera_id] = camera_config
            
            logger.info(f"从 {file_path} 成功加载 {len(self.camera_configs)} 个摄像头配置")
            
            # 如果管理器正在运行，重新应用配置
            if self.running:
                self._reapply_configs()
            
            return True
            
        except Exception as e:
            logger.error(f"加载摄像头配置失败: {str(e)}")
            return False
    
    def _reapply_configs(self):
        """重新应用配置，确保运行的摄像头与配置一致"""
        try:
            # 获取当前活跃的摄像头
            active_cameras = set(self.get_active_cameras())
            configured_cameras = set(self.camera_configs.keys())
            
            # 启动新配置的摄像头
            for camera_id in configured_cameras - active_cameras:
                logger.info(f"启动新配置的摄像头: {camera_id}")
                self.start_camera(camera_id)
            
            # 停止不再配置的摄像头
            for camera_id in active_cameras - configured_cameras:
                logger.info(f"停止不再配置的摄像头: {camera_id}")
                self.stop_camera(camera_id)
            
            # 更新现有摄像头的配置
            for camera_id in configured_cameras & active_cameras:
                self.update_camera_config(camera_id, self.camera_configs[camera_id])
                
        except Exception as e:
            logger.error(f"重新应用配置失败: {str(e)}")
    
    def get_system_status(self) -> Dict[str, Any]:
        """获取系统状态
        
        Returns:
            系统状态信息
        """
        camera_statuses = self.get_all_camera_status()
        active_count = sum(1 for status in camera_statuses.values() if status.get('is_running', False))
        
        return {
            'running': self.running,
            'initialized': self.initialized,
            'total_cameras': len(self.camera_configs),
            'active_cameras': active_count,
            'inactive_cameras': len(self.camera_configs) - active_count,
            'camera_statuses': camera_statuses,
            'timestamp': datetime.now().isoformat()
        }
    
    def __del__(self):
        """析构函数，确保资源正确释放"""
        try:
            self.stop()
        except:
            pass  # 忽略析构函数中的错误

# 创建全局视频管理器实例
_video_manager = None

# 用于线程同步的锁
_video_manager_lock = threading.RLock()

def get_video_manager(config: Dict[str, Any] = None) -> VideoManager:
    """获取视频管理器实例（单例模式）
    
    Args:
        config: 配置参数（仅在第一次调用时有效）
        
    Returns:
        VideoManager实例
    """
    global _video_manager
    
    with _video_manager_lock:
        if _video_manager is None:
            _video_manager = VideoManager(config)
    
    return _video_manager